package edu.xidian.onlinedocument.repository.specification;

import edu.xidian.onlinedocument.entity.DocumentData;
import edu.xidian.onlinedocument.entity.UserData;
import edu.xidian.onlinedocument.handler.excpetions.custom.CustomException;
import edu.xidian.onlinedocument.views.ResultCode;
import edu.xidian.onlinedocument.repository.UserDataJPARepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.StringUtils;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Component
public class UserSpecification {
    private final UserDataJPARepository userDataJPARepository;

    @Autowired
    public UserSpecification(UserDataJPARepository userDataJPARepository) {
        this.userDataJPARepository = userDataJPARepository;
    }

    public UserData findOneUserDataWithDocumentByUserNum(String userNum) {
        Specification<UserData> specification = new Specification<>() {
            /**
             * 重写查询条件，其中的三个参数都不是要传入的，而是要在toPredicate里重新设定其值
             * root相当于是"select * from 表名"的最原始查询语句，而root.join("另一个表", left join)相当于"select * from 表1 left join 表2
             * query相当于是修改select和where的内容，如query.distinct相当于"select distinct * from 表名"
             * criteriaBuilder相当于是用一些给定的方法构造where的内容，并以Predicate类型返回
             * 最后返回Predicate类型的值就是最终的查询语句内容
             * @param root
             * @param query
             * @param criteriaBuilder
             * @return Predicate
             */
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
                if(StringUtils.isBlank(userNum)){
                    throw new CustomException(ResultCode.USER_ID_NOT_EXIST);
                }
                Join<UserData, DocumentData> userWithDoc = root.join("documentData", JoinType.LEFT);
                // Path<Object> userNumPath = userWithDoc.get("userNum");
                return criteriaBuilder.equal(root.get("userNum"), userNum);
            }
        };
        Optional<UserData> opt = userDataJPARepository.findOne(specification);
        return opt.get();
    }

    public List<UserData> findAllUserDataWithDocument(/*String userNum*/){
        Specification<UserData> specification = new Specification<>() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicateList = new ArrayList<>();
                // 注意：root.join("连接字段", 连接方式)中的连接字段指的是UserData类中的Document类型的成员变量的变量名
                Join<UserData, DocumentData> userWithDoc = root.join("documentData", JoinType.LEFT);
                query.distinct(true);       // 去重
                return userWithDoc.getOn();
            }
        };
        return userDataJPARepository.findAll(specification);
    }
}
